@node Condition system
@section Condition system

@stindex exceptions
@stindex conditions
As of version 1.3 (different from all older versions), Scheme48
supports two different condition systems.  One of them, the original
one, is a simple system where conditions are represented as tagged
lists.  This section documents the original one.  The new condition
system is [SRFI 34, 35], and there is a complicated translation layer
between the old one, employed by the run-time system, and the new one,
which is implemented in a layer high above that as a library, but a
library which is always loaded in the usual development environment.
See the [SRFI 34, 35] documents for documentation of the new condition
system.  [SRFI 34] is available from the @code{exceptions} structure;
SRFI 35, from the @code{conditions} structure.

@strong{Note:} The condition system changed in Scheme48 version 1.3.
While the old one is still available, the names of the structures that
implement it changed.  @code{Signals} is now @code{simple-signals},
and @code{conditions} is now @code{simple-conditions}.  The structure
that @code{signals} @emph{now} names implements the same interface,
but with [SRFI 34, 35] underlying it.  The structure that the name
@code{conditions} @emph{now} identifies [SRFI 35].  You will have to
update all old code that relied on the old @code{signals} and
@code{conditions} structure either by using those structures' new
names or by invasively modifying all code to use [SRFI 34, 35].  Also,
the only way to completely elide the use of the SRFIs is to evaluate
this in an environment with the @code{exceptions-internal} and
@code{vm-exceptions} structure open:

@lisp
(begin (initialize-vm-exceptions! really-signal-condition)
       ;; INITIALIZE-VM-EXCEPTIONS! returns a very large object,
       ;; which we probably don't want printed at the REPL.
       #t)@end lisp

@subsection Signalling, handling, and representing conditions

@cindex conditions
@cindex exceptions
@cindex errors
@cindex warnings
@cindex signalling conditions
@cindex condition types
@cindex condition handlers
Scheme48 provides a simple condition system.@footnote{Note, however,
that Scheme48's condition system is likely to be superseded in the near
future by [SRFI 34, SRFI 35].}  @dfn{Conditions} are objects that
describe exceptional situations. Scheme48 keeps a registry of
@dfn{condition types}, which just have references to their supertypes.
Conditions are simple objects that contain only two fields, the type
and the type-specific data (the @dfn{stuff}).  Accessor procedures
should be defined for particular condition types to extract the data
contained within the `stuff' fields of instances of of those condition
types.  Condition types are represented as symbols.  @dfn{Condition
handlers} are part of the system's dynamic context; they are used to
handle exceptional situations when conditions are signalled that
describe such exceptional situations.  @dfn{Signalling} a condition
signals that an exceptional situation occurred and invokes the current
condition handler on the condition.

Scheme48's condition system is split up into three structures:

@table @code
@item simple-signals
Exports procedures to signal conditions and construct conditions, as
well as some utilities for common kinds of conditions.

@item handle
Exports facilities for handling signalled conditions.

@item simple-conditions
The system of representing conditions as objects.
@end table

@stindex simple-signals
The @code{simple-signals} structure exports these procedures:

@deffn procedure make-condition type-name stuff @returns{} condition
The condition object constructor.
@end deffn

@deffn procedure signal-condition condition @returns{} values (may not return)
@deffnx procedure signal type-name stuff @dots{} @returns{} values (may not return)
@code{Signal-condition} signals the given condition.  @code{Signal} is
a convenience atop the common conjunction of @code{signal-condition}
and @code{make-condition}: it constructs a condition with the given
type name and stuff, whereafter it signals that condition with
@code{signal-condition}.
@end deffn

@deffn procedure error message irritant @dots{} @returns{} values (may not return)
@deffnx procedure warn message irritant @dots{} @returns{} values (may not return)
@deffnx procedure syntax-error message irritant @dots{} @returns{} expression (may not return)
@deffnx procedure call-error message irritant @dots{} @returns{} values (may not return)
@deffnx procedure note message irritant @dots{} @returns{} values (may not return)
Conveniences for signalling standard condition types.  These procedures
generally either do not return or return an unspecified value, unless
specified to by a user of the debugger.  @code{Syntax-error} returns
the expression @code{(quote syntax-error)}, if the condition handler
returns to @code{syntax-error} in the first place.

@cindex error messages
@cindex condition messages
By convention, the message should be lowercased (@ie{} the first word
should not be capitalized), and it should not end with punctuation.
The message is typically not a complete sentence.  For example, these
all follow Scheme48's convention:

@itemize @w{}
@item argument type error
@item wrong number of arguments
@item invalid syntax
@item ill-typed right-hand side
@item out of memory, unable to continue
@end itemize

These, on the other hand, do not follow the convention and should be
avoided:

@itemize @w{}
@item Argument type error:
@item An argument of the wrong type was passed.
@item possible type mismatch:
@item Luser is an idiot!
@end itemize

Elaboration on a message is performed usually by wrapping an irritant
in a descriptive list.  For example, one might write:

@lisp
(error "invalid argument"
       '(not a pair)
       `(while calling ,frobbotz)
       `(received ,object))@end lisp

@noindent
This might be printed as:

@example
Error: invalid argument
       (not a pair)
       (while calling #@{Procedure 123 (frobbotz in ...)@})
       (received #(a b c d))@end example
@end deffn

@cindex installing condition handlers
@stindex handle
The @code{handle} structure exports the following procedures:

@deffn procedure with-handler handler thunk @returns{} values
Sets up @var{handler} as the condition handler for the dynamic extent
of @var{thunk}.  @var{Handler} should be a procedure of two arguments:
the condition that was signalled and a procedure of zero arguments that
propagates the condition up to the next dynamically enclosing handler.
When a condition is signalled, @var{handler} is tail-called from the
point that the condition was signalled at.  Note that, because
@var{handler} is tail-called at that point, it will @emph{return} to
that point also.

@strong{Warning:} @code{With-handler} is potentially very dangerous.
If an exception occurs and a condition is raised in the handler, the
handler itself will be called with that new condition!  Furthermore,
the handler may accidentally return to an unexpecting signaller, which
can cause very confusing errors.  Be careful with @code{with-handler};
to be perfectly safe, it might be a good idea to throw back out to
where the handler was initially installed before doing anything:

@lisp
((call-with-current-continuation
   (lambda (k)
     (lambda ()
       (with-handler (lambda (c propagate)
                       (k (lambda () @var{handler body})))
         (lambda () @var{body}))))))@end lisp
@end deffn

@deffn procedure ignore-errors thunk @returns{} values or condition
@deffnx procedure report-errors-as-warnings thunk message irritant @dots{} @returns{} values
@code{Ignore-errors} sets up a condition handler that will return error
conditions to the point where @code{ignore-errors} was called, and
propagate all other conditions.  If no condition is signalled during
the dynamic extent of @var{thunk}, @code{ignore-errors} simply returns
whatever @var{thunk} returned.  @code{Report-errors-as-warnings}
downgrades errors to warnings while executing @var{thunk}.  If an error
occurs, a warning is signalled with the given message, and a list of
irritants constructed by adding the error condition to the end of the
list @var{irritant} @dots{}.
@end deffn

@cindex conditions
@cindex condition types
@stindex simple-conditions
Finally, the @code{simple-conditions} structure defines the condition
type system.  (Note that conditions themselves are constructed only by
@code{make-condition} (and @code{signal}) from the
@code{simple-signals} structure.)  Conditions are very basic values
that have only two universally defined fields: the type and the stuff.
The type is a symbol denoting a condition type.  The type is specified
in the first argument to @code{make-condition} or @code{signal}.  The
stuff field contains whatever a particular condition type stores in
conditions of that type.  The stuff field is always a list; it is
created from the arguments after the first to @code{make-condition} or
@code{signal}.  Condition types are denoted by symbols, kept in a
global registry that maps condition type names to their supertype
names.

@deffn procedure define-condition-type name supertype-names @returns{} unspecified
Registers the symbol @var{name} as a condition type.  Its supertypes
are named in the list @var{supertype-names}.
@end deffn

@deffn procedure condition-predicate ctype-name @returns{} predicate
Returns a procedure of one argument that returns @code{#t} if that
argument is a condition whose type's name is @var{ctype-name} or
@code{#f} if not.
@end deffn

@deffn procedure condition-type condition @returns{} type-name
@deffnx procedure condition-stuff condition @returns{} list
Accessors for the two immutable fields of conditions.
@end deffn

@deffn procedure error? condition @returns{} boolean
@deffnx procedure warning? condition @returns{} boolean
@deffnx procedure note? condition @returns{} boolean
@deffnx procedure syntax-error? condition @returns{} boolean
@deffnx procedure call-error? condition @returns{} boolean
@deffnx procedure read-error? condition @returns{} boolean
@deffnx procedure interrupt? condition @returns{} boolean
Condition predicates for built-in condition types.
@end deffn

@deffn procedure make-exception opcode reason arguments @returns{} exception
@deffnx procedure exception? condition @returns{} boolean
@deffnx procedure exception-opcode exception @returns{} integer-opcode
@deffnx procedure exception-reason exception @returns{} symbol
@deffnx procedure exception-arguments exception @returns{} list
@dfn{Exceptions} represent run-time errors in the Scheme48 VM.  They
contain information about what opcode the VM was executing when it
happened, what the reason for the exception occurring was, and the
relevant arguments.
@c @xref{VM exceptions}.
@end deffn

@subsection Displaying conditions

@cindex printing conditions
@cindex displaying conditions
The @code{display-conditions} structure is also relevant in this
section.

@deffn procedure display-condition condition port @returns{} unspecified
Prints @var{condition} to @var{port} for a user to read.  For example:

@lisp
(display-condition (make-condition 'error
                     "Foo bar baz"
                     'quux
                     '(zot mumble: frotz))
                   (current-output-port))
    @print{} Error: Foo bar baz
    @print{}        quux
    @print{}        (zot mumble: frotz)@end lisp
@end deffn

@defvr {method table} &disclose-condition condition @returns{} disclosed
Method table (@pxref{Generic dispatch system}) for a generic procedure
(not exposed) used to translate a condition object into a more readable
format.  @xref{Writer}.
@end defvr

@deffn procedure limited-write object port max-depth max-length @returns{} unspecified
A utility for avoiding excessive output: prints @var{object} to
@var{port}, but will never print more than @var{max-length} of a
subobject's components, leaving a @code{---} after the last component,
and won't recur further down the object graph from the vertex
@var{object} beyond @var{max-depth}, instead printing an octothorpe
(@code{#}).

@lisp
(let ((x (cons #f #f)))
  (set-car! x x)
  (set-cdr! x x)
  (limited-write x (current-output-port) 2 2))
    @print{} ((# # ---) (# # ---) ---)@end lisp
@end deffn
